#include "JSValueWrapper.h"

namespace AwesomiumDotNet
{
	ref class WebView;

	typedef void (*BeginLoadingCallback) (const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType);
	typedef void (*BeginNavigationCallback) (const std::string& url, const std::wstring& frameName);
	typedef void (*ChangeCursorCallback) (const HCURSOR& cursor);
	typedef void (*ChangeKeyboardFocusCallback) (bool isFocused);
	typedef void (*ChangeTargetUrlCallback) (const std::string& url);
	typedef void (*ChangeTooltipCallback) (const std::wstring& tooltip);
	typedef void (*FinishLoadingCallback) ();
	typedef void (*ReceiveTitleCallback) (const std::wstring& title, const std::wstring& frameName);
#ifdef VERSION_108
	typedef void (*CallbackCallback) (const std::string& name, const Awesomium::JSArguments& args);
#else
	typedef void (*CallbackCallback) (const std::wstring& objectName, const std::wstring& callbackName, const Awesomium::JSArguments& args);
	typedef void (*OpenExternalLinkCallback) (const std::string& url, const std::wstring& source);
#endif

	delegate void BeginLoadingDelegate (const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType);
	delegate void BeginNavigationDelegate (const std::string& url, const std::wstring& frameName);
	delegate void ChangeCursorDelegate (const HCURSOR& cursor);
	delegate void ChangeKeyboardFocusDelegate (bool isFocused);
	delegate void ChangeTargetUrlDelegate (const std::string& url);
	delegate void ChangeTooltipDelegate (const std::wstring& tooltip);
	delegate void FinishLoadingDelegate ();
	delegate void ReceiveTitleDelegate (const std::wstring& title, const std::wstring& frameName);
#ifdef VERSION_108
	delegate void CallbackDelegate (const std::string& name, const Awesomium::JSArguments& args);
#else
	delegate void CallbackDelegate (const std::wstring& objectName, const std::wstring& callbackName, const Awesomium::JSArguments& args);
	delegate void OpenExternalLinkDelegate (const std::string& url, const std::wstring& source);
#endif

	class WebViewListenerWrapper : public Awesomium::WebViewListener
	{
	public:
		BeginLoadingCallback cb_onBeginLoading;
		BeginNavigationCallback cb_onBeginNavigation;
		CallbackCallback cb_onCallback;
		ChangeCursorCallback cb_onChangeCursor;
		ChangeKeyboardFocusCallback cb_onChangeKeyboardFocus;
		ChangeTargetUrlCallback cb_onChangeTargetURL;
		ChangeTooltipCallback cb_onChangeTooltip;
		FinishLoadingCallback cb_onFinishLoading;
		ReceiveTitleCallback cb_onReceiveTitle;
#ifndef VERSION_108
		OpenExternalLinkCallback cb_onOpenExternalLink;
#endif

	public:
		WebViewListenerWrapper()
		{
		}

#ifdef VERSION_108
		void onBeginLoading(const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType)
		{
			cb_onBeginLoading(url, frameName, statusCode, mimeType);
		}

		void onBeginNavigation(const std::string& url, const std::wstring& frameName)
		{
			cb_onBeginNavigation(url, frameName);
		}

		void onFinishLoading()
		{
			cb_onFinishLoading();
		}

		void onCallback(const std::string& name, const Awesomium::JSArguments& args)
		{
			cb_onCallback(name, args);
		}

		void onReceiveTitle(const std::wstring& title, const std::wstring& frameName)
		{
			cb_onReceiveTitle(title, frameName);
		}

		void onChangeTooltip(const std::wstring& tooltip)
		{
			cb_onChangeTooltip(tooltip);
		}

		void onChangeCursor(const HCURSOR& cursor)
		{
			cb_onChangeCursor(cursor);
		}

		void onChangeKeyboardFocus(bool isFocused)
		{
			cb_onChangeKeyboardFocus(isFocused);
		}

		void onChangeTargetURL(const std::string& url)
		{
			cb_onChangeTargetURL(url);
		}
#else
		void onBeginLoading(Awesomium::WebView* caller, const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType)
		{
			cb_onBeginLoading(url, frameName, statusCode, mimeType);
		}

		void onBeginNavigation(Awesomium::WebView* caller, const std::string& url, const std::wstring& frameName)
		{
			cb_onBeginNavigation(url, frameName);
		}

		void onFinishLoading(Awesomium::WebView* caller)
		{
			cb_onFinishLoading();
		}

		void onCallback(Awesomium::WebView* caller, const std::wstring& objectName, const std::wstring& callbackName, const Awesomium::JSArguments& args)
		{
			cb_onCallback(objectName, callbackName, args);
		}

		void onReceiveTitle(Awesomium::WebView* caller, const std::wstring& title, const std::wstring& frameName)
		{
			cb_onReceiveTitle(title, frameName);
		}

		void onChangeTooltip(Awesomium::WebView* caller, const std::wstring& tooltip)
		{
			cb_onChangeTooltip(tooltip);
		}

		void onChangeCursor(Awesomium::WebView* caller, const HCURSOR& cursor)
		{
			cb_onChangeCursor(cursor);
		}

		void onChangeKeyboardFocus(Awesomium::WebView* caller, bool isFocused)
		{
			cb_onChangeKeyboardFocus(isFocused);
		}
	
		void onChangeTargetURL(Awesomium::WebView* caller, const std::string& url)
		{
			cb_onChangeTargetURL(url);
		}

		void onOpenExternalLink(Awesomium::WebView* caller, const std::string& url, const std::wstring& source)
		{
			cb_onOpenExternalLink(url, source);
		}
#endif
	};

	public ref class BeginLoadingEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The URL of the frame that is being loaded.</summary>
		property String^ Url;
		/// <summary>The name of the frame that this event originated from.</summary>
		property String^ FrameName;
		/// <summary>The HTTP status code returned by the server.</summary>
		property int StatusCode;
		/// <summary>The mime-type of the content that is being loaded.</summary>
		property String^ MimeType;

		BeginLoadingEventArgs(AwesomiumDotNet::WebView^ webView, String^ url, String^ frameName, int statusCode, String^ mimeType) {
			this->WebView = webView;
			this->Url = url;
			this->FrameName = frameName;
			this->StatusCode = statusCode;
			this->MimeType = mimeType;
		}
	};

	public ref class BeginNavigationEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The URL that is being navigated to.</summary>
		property String^ Url;
		/// <summary>The name of the frame that this event originated from.</summary>
		property String^ FrameName;

		BeginNavigationEventArgs(AwesomiumDotNet::WebView^ webView, String^ url, String^ frameName) {
			this->WebView = webView;
			this->Url = url;
			this->FrameName = frameName;
		}
	};

#ifdef VERSION_108
	public ref class CallbackEventArgs : System::EventArgs
	{
	private:
		Collection<JSValue^>^ _args;

	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The name of the client callback that was invoked (specifically, "Client._this_name_here_(...)").</summary>
		property String^ Name;
		/// <summary>The arguments passed to the callback.</summary>
		property Collection<JSValue^>^ Args
		{
			Collection<JSValue^>^ get() { return _args; }
		}

		CallbackEventArgs(AwesomiumDotNet::WebView^ webView, String^ name, Collection<JSValue^>^ args) {
			this->WebView = webView;
			this->Name = name;
			this->_args = args;
		}
	};
#else
	public ref class CallbackEventArgs : System::EventArgs
	{
	private:
		Collection<JSValue^>^ _args;

	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The name of the Javascript Object that contains the invoked callback.</summary>
		property String^ ObjectName;
		/// <summary>The name of the callback that was invoked (must have been previously bound via WebView.SetObjectCallback).</summary>
		property String^ CallbackName;
		/// <summary>The arguments passed to the callback.</summary>
		property Collection<JSValue^>^ Args
		{
			Collection<JSValue^>^ get() { return _args; }
		}
		
		CallbackEventArgs(AwesomiumDotNet::WebView^ webView, String^ objectName, String^ callbackName, Collection<JSValue^>^ args) {
			this->WebView = webView;
			this->ObjectName = objectName;
			this->CallbackName = callbackName;
			this->_args = args;
		}
	};
#endif

	public ref class ChangeCursorEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The cursor handle/type.</summary>
		property Windows::Forms::Cursor^ Cursor;

		ChangeCursorEventArgs(AwesomiumDotNet::WebView^ webView, Windows::Forms::Cursor^ cursor) {
			this->WebView = webView;
			this->Cursor = cursor;
		}
	};

	public ref class ChangeKeyboardFocusEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>Whether or not the keyboard is currently focused.</summary>
		property bool IsFocused;

		ChangeKeyboardFocusEventArgs(AwesomiumDotNet::WebView^ webView, bool isFocused) {
			this->WebView = webView;
			this->IsFocused = isFocused;
		}
	};

	public ref class ChangeTargetUrlEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The updated target URL (or empty if the target URL is cleared).</summary>
		property String^ Url;

		ChangeTargetUrlEventArgs(AwesomiumDotNet::WebView^ webView, String^ url) {
			this->WebView = webView;
			this->Url = url;
		}
	};

	public ref class ChangeTooltipEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The tooltip text (or, is an empty string when the tooltip should disappear).</summary>
		property String^ Tooltip;

		ChangeTooltipEventArgs(AwesomiumDotNet::WebView^ webView, String^ tooltip) {
			this->WebView = webView;
			this->Tooltip = tooltip;
		}
	};

	public ref class FinishLoadingEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;

		FinishLoadingEventArgs(AwesomiumDotNet::WebView^ webView) {
			this->WebView = webView;
		}
	};

	public ref class ReceiveTitleEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The page title.</summary>
		property String^ Title;
		/// <summary>The name of the frame that this event originated from.</summary>
		property String^ FrameName;

		ReceiveTitleEventArgs(AwesomiumDotNet::WebView^ webView, String^ title, String^ frameName) {
			this->WebView = webView;
			this->Title = title;
			this->FrameName = frameName;
		}
	};

#ifndef VERSION_108
	public ref class OpenExternalLinkEventArgs : System::EventArgs
	{
	public:
		/// <summary>The WebView that the event originated from.</summary>
		property WebView^ WebView;
		/// <summary>The URL of the external link.</summary>
		property String^ Url;
		/// <summary>
		/// If the external link originated from a call to window.open(), this value
		/// is "window.open". Else, if the link originated from a Flash plugin, this
		/// value is "flash". Otherwise, this value is the name of the frame that
		/// contains the link.
		/// </summary>
		property String^ Source;

		OpenExternalLinkEventArgs(AwesomiumDotNet::WebView^ webView, String^ url, String^ source) {
			this->WebView = webView;
			this->Url = url;
			this->Source = source;
		}
	};
#endif

}
